package org.eiahe.hr.salary.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.ehe.common.core.utils.MapstructUtils;
import org.ehe.common.core.utils.StringUtils;
import org.ehe.common.mybatis.core.page.PageQuery;
import org.ehe.common.mybatis.core.page.TableDataInfo;
import org.ehe.system.service.ISysDeptService;
import org.eiahe.hr.salary.domain.SalaryCorrectionRecord;
import org.eiahe.hr.salary.domain.SalaryStructure;
import org.eiahe.hr.salary.domain.bo.SalaryCorrectionRecordBo;
import org.eiahe.hr.salary.domain.vo.SalaryCorrectionRecordVo;
import org.eiahe.hr.salary.mapper.SalaryCorrectionRecordMapper;
import org.eiahe.hr.salary.mapper.SalaryStructureMapper;
import org.eiahe.hr.salary.service.ISalaryCorrectionRecordService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.Date;
import java.util.List;

/**
 * 薪资纠错记录Service业务层处理
 *
 * @author zhangnn
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class SalaryCorrectionRecordServiceImpl implements ISalaryCorrectionRecordService {

    private final SalaryCorrectionRecordMapper baseMapper;
    private final SalaryStructureMapper salaryStructureMapper;
    private final ISysDeptService deptService;

    @Override
    public SalaryCorrectionRecordVo queryById(Long correctionId) {
        return baseMapper.selectVoById(correctionId);
    }

    @Override
    public List<SalaryCorrectionRecordVo> queryList(SalaryCorrectionRecordBo bo) {
        LambdaQueryWrapper<SalaryCorrectionRecord> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    @Override
    public TableDataInfo<SalaryCorrectionRecordVo> queryPageList(SalaryCorrectionRecordBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<SalaryCorrectionRecord> lqw = buildQueryWrapper(bo);
        IPage<SalaryCorrectionRecordVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(page);
    }

    /**
     * 构建查询条件
     *
     * @param bo 薪资纠错记录业务对象
     * @return 查询条件
     */
    private LambdaQueryWrapper<SalaryCorrectionRecord> buildQueryWrapper(SalaryCorrectionRecordBo bo) {
        LambdaQueryWrapper<SalaryCorrectionRecord> lqw = Wrappers.lambdaQuery();
        lqw.eq(StringUtils.isNotBlank(bo.getEmployeeNo()), SalaryCorrectionRecord::getEmployeeNo, bo.getEmployeeNo());
        lqw.eq(StringUtils.isNotBlank(bo.getEmployeeName()), SalaryCorrectionRecord::getEmployeeName,
                bo.getEmployeeName());
        lqw.eq(StringUtils.isNotBlank(bo.getYearMonth()), SalaryCorrectionRecord::getYearMonth, bo.getYearMonth());
        lqw.eq(StringUtils.isNotBlank(bo.getCorrectionType()), SalaryCorrectionRecord::getCorrectionType,
                bo.getCorrectionType());
        lqw.eq(StringUtils.isNotBlank(bo.getApprovalStatus()), SalaryCorrectionRecord::getApprovalStatus,
                bo.getApprovalStatus());
        lqw.orderByDesc(SalaryCorrectionRecord::getCreateTime);
        return lqw;
    }

    @Override
    public Boolean insertByBo(SalaryCorrectionRecordBo bo) {
        SalaryCorrectionRecord add = MapstructUtils.convert(bo, SalaryCorrectionRecord.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setCorrectionId(add.getCorrectionId());
        }
        return flag;
    }

    @Override
    public Boolean updateByBo(SalaryCorrectionRecordBo bo) {
        SalaryCorrectionRecord update = MapstructUtils.convert(bo, SalaryCorrectionRecord.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     *
     * @param entity 实体类数据
     */
    private void validEntityBeforeSave(SalaryCorrectionRecord entity) {
        // 校验员工工号是否存在
        if (StringUtils.isBlank(entity.getEmployeeNo())) {
            throw new RuntimeException("员工工号不能为空");
        }

        // 校验年月格式
        if (StringUtils.isBlank(entity.getYearMonth()) || entity.getYearMonth().length() != 6 ||
                !entity.getYearMonth().matches("\\d{6}")) {
            throw new RuntimeException("年月格式不正确，请使用yyyyMM格式");
        }

        // 校验纠错类型
        if (StringUtils.isBlank(entity.getCorrectionType()) ||
                (!"1".equals(entity.getCorrectionType()) && !"2".equals(entity.getCorrectionType())
                        && !"3".equals(entity.getCorrectionType()))) {
            throw new RuntimeException("纠错类型只能是1(冲减)、2(状态回退)或3(数据修正)");
        }

        // 校验状态合法性
        if (StringUtils.isNotBlank(entity.getApprovalStatus()) &&
                !"0".equals(entity.getApprovalStatus()) && !"1".equals(entity.getApprovalStatus()) &&
                !"2".equals(entity.getApprovalStatus())) {
            throw new RuntimeException("审批状态只能是0(待审批)、1(已通过)或2(已拒绝)");
        }
    }

    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids) {
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean approveCorrection(Long correctionId, String approvalStatus, String approver,
            String approvalOpinion) {
        try {
            // 查询纠错记录
            SalaryCorrectionRecord correction = baseMapper.selectById(correctionId);
            if (correction == null) {
                return false;
            }

            // 检查记录状态是否为待审批
            if (!"0".equals(correction.getApprovalStatus())) {
                return false;
            }

            // 更新审批信息
            correction.setApprovalStatus(approvalStatus); // 1已通过或2已拒绝
            correction.setApprover(approver);
            correction.setApprovalTime(new Date());
            correction.setApprovalOpinion(approvalOpinion);

            boolean result = baseMapper.updateById(correction) > 0;

            // 如果审批通过成功，则自动执行纠错操作
            if (result && "1".equals(approvalStatus)) {
                executeCorrection(correctionId);
            }

            return result;
        } catch (Exception e) {
            log.error("审批薪资纠错记录失败", e);
            throw new RuntimeException("审批薪资纠错记录失败", e);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean executeCorrection(Long correctionId) {
        try {
            // 查询纠错记录
            SalaryCorrectionRecord correction = baseMapper.selectById(correctionId);
            if (correction == null) {
                return false;
            }

            // 检查记录是否已审批通过
            if (!"1".equals(correction.getApprovalStatus())) {
                return false;
            }

            // 根据纠错类型执行不同的操作
            String correctionType = correction.getCorrectionType();
            Long optId = correction.getCorrectionId();
            if (correctionType.equals("1")) {
                optId = executeDeduction(correction);
            } else if (correctionType.equals("2")) {
                optId = executeStatusRollback(correction);
            } else if(correctionType.equals("3")){
                optId =executeDataCorrection(correction);
            } else {
                throw new RuntimeException("未知的纠错类型: " + correctionType);
            }
            correction.setOriginalStructureId(optId);
            this.baseMapper.updateById(correction);
            return true;
        } catch (Exception e) {
            log.error("执行薪资纠错操作失败", e);
            throw new RuntimeException("执行薪资纠错操作失败", e);
        }
    }

    /**
     * 执行冲减操作
     *
     * @param correction 纠错记录
     * @return 是否成功
     */
    private Long executeDeduction(SalaryCorrectionRecord correction) {
        try {
            // 查询原薪资记录
            SalaryStructure originalStructure = salaryStructureMapper.selectById(correction.getOriginalStructureId());
            if (originalStructure == null) {
                throw new RuntimeException("未找到原薪资记录");
            }

            // 创建冲减记录（负值）
            SalaryStructure deductionStructure = new SalaryStructure();
            deductionStructure.setTenantId(originalStructure.getTenantId());
            deductionStructure.setEmployeeNo(originalStructure.getEmployeeNo());
            deductionStructure.setEmployeeName(originalStructure.getEmployeeName());
            deductionStructure.setBankCardNo(originalStructure.getBankCardNo());
            deductionStructure.setBankName(originalStructure.getBankName());
            deductionStructure.setDepartment(originalStructure.getDepartment());
            deductionStructure.setYearMonth(correction.getYearMonth());

            // 设置冲减金额（负值）
            BigDecimal deductionAmount = correction.getCorrectionAmount() != null
                    ? correction.getCorrectionAmount().negate()
                    : BigDecimal.ZERO;

            // 根据原薪资结构设置冲减后的各项金额
            deductionStructure.setJobLevelSalary(originalStructure.getJobLevelSalary());
            deductionStructure.setBaseSalary(deductionAmount); // 冲减基本工资
            deductionStructure.setPositionSalary(originalStructure.getPositionSalary());
            deductionStructure.setPerformanceSalary(originalStructure.getPerformanceSalary());
            deductionStructure.setDutyAllowance(originalStructure.getDutyAllowance());
            deductionStructure.setShouldAttendanceDays(originalStructure.getShouldAttendanceDays());
            deductionStructure.setAbsenceDays(originalStructure.getAbsenceDays());
            deductionStructure.setPaidAttendanceDays(originalStructure.getPaidAttendanceDays());
            deductionStructure.setAbsenceDeduction(originalStructure.getAbsenceDeduction());
            deductionStructure.setMealAllowance(originalStructure.getMealAllowance());
            deductionStructure.setOtherAdjustment(originalStructure.getOtherAdjustment());
            deductionStructure.setMealDeduction(originalStructure.getMealDeduction());

            // 计算冲减后的应发工资
            BigDecimal grossSalary = deductionAmount;
            if (originalStructure.getGrossSalary() != null) {
                grossSalary = grossSalary.add(originalStructure.getGrossSalary());
            }
            deductionStructure.setGrossSalary(grossSalary);

            deductionStructure.setPensionDeduction(originalStructure.getPensionDeduction());
            deductionStructure.setUnemploymentDeduction(originalStructure.getUnemploymentDeduction());
            deductionStructure.setMedicalDeduction(originalStructure.getMedicalDeduction());
            deductionStructure.setMajorMedicalDeduction(originalStructure.getMajorMedicalDeduction());
            deductionStructure.setSocialInsurancePersonal(originalStructure.getSocialInsurancePersonal());
            deductionStructure.setHousingFundPersonal(originalStructure.getHousingFundPersonal());

            // 计算冲减后的社保公积金合计
            BigDecimal socialHousingTotal = BigDecimal.ZERO;
            if (originalStructure.getSocialHousingTotal() != null) {
                socialHousingTotal = originalStructure.getSocialHousingTotal();
            }
            deductionStructure.setSocialHousingTotal(socialHousingTotal);

            // 计算冲减后的税前工资
            BigDecimal taxableSalary = grossSalary;
            if (socialHousingTotal.compareTo(BigDecimal.ZERO) > 0) {
                taxableSalary = taxableSalary.subtract(socialHousingTotal);
            }
            deductionStructure.setTaxableSalary(taxableSalary);

            deductionStructure.setPersonalTax(originalStructure.getPersonalTax());

            // 计算冲减后的实发工资
            BigDecimal netSalary = taxableSalary;
            if (originalStructure.getPersonalTax() != null) {
                netSalary = netSalary.subtract(originalStructure.getPersonalTax());
            }
            deductionStructure.setNetSalary(netSalary);

            deductionStructure.setStatus("0"); // 正常状态
            deductionStructure.setRemark("薪资冲减操作，原记录ID: " + correction.getOriginalStructureId());

            // 插入冲减记录
            salaryStructureMapper.deleteById(originalStructure);
            salaryStructureMapper.insert(deductionStructure);
            return deductionStructure.getStructureId();
        } catch (Exception e) {
            // 记录日志
            log.error("执行冲减操作失败", e);
            throw new RuntimeException("执行冲减操作失败", e);
        }
    }

    /**
     * 执行状态回退操作
     *
     * @param correction 纠错记录
     * @return 是否成功
     */
    private Long executeStatusRollback(SalaryCorrectionRecord correction) {
        try {
            // 查询原薪资记录
            SalaryStructure originalStructure = salaryStructureMapper.selectById(correction.getOriginalStructureId());
            if (originalStructure == null) {
                throw new RuntimeException("未找到原薪资记录");
            }

            // 更新状态为原状态
            originalStructure.setStatus(correction.getOriginalStatus());
            originalStructure.setRemark("状态回退操作，原状态: " + correction.getOriginalStatus() +
                    "，新状态: " + correction.getNewStatus());

            salaryStructureMapper.updateById(originalStructure);
            return originalStructure.getStructureId();
        } catch (Exception e) {
            // 记录日志
            log.error("执行状态回退操作失败", e);
            throw new RuntimeException("执行状态回退操作失败", e);
        }
    }

    /**
     * 执行数据修正操作
     *
     * @param correction 纠错记录
     * @return 是否成功
     */
    private Long executeDataCorrection(SalaryCorrectionRecord correction) {
        try {
            // 查询原薪资记录
            SalaryStructure originalStructure = salaryStructureMapper.selectById(correction.getOriginalStructureId());
            if (originalStructure == null) {
                throw new RuntimeException("未找到原薪资记录");
            }

            // 更新状态为封存
            originalStructure.setStatus("1"); // 封存
            originalStructure.setDelFlag("1"); //删除
            originalStructure.setRemark("数据修正操作，原记录已封存");

            boolean updateResult = salaryStructureMapper.updateById(originalStructure) > 0;

            SalaryStructure correctedStructure = new SalaryStructure();
            if (updateResult) {
                // 创建新的修正记录
                correctedStructure.setTenantId(originalStructure.getTenantId());
                correctedStructure.setEmployeeNo(originalStructure.getEmployeeNo());
                correctedStructure.setEmployeeName(originalStructure.getEmployeeName());
                correctedStructure.setBankCardNo(originalStructure.getBankCardNo());
                correctedStructure.setBankName(originalStructure.getBankName());
                correctedStructure.setDepartment(originalStructure.getDepartment());
                correctedStructure.setYearMonth(correction.getYearMonth());

                // 使用原薪资结构的数据
                correctedStructure.setJobLevelSalary(originalStructure.getJobLevelSalary());
                correctedStructure.setBaseSalary(originalStructure.getBaseSalary());
                correctedStructure.setPositionSalary(originalStructure.getPositionSalary());
                correctedStructure.setPerformanceSalary(originalStructure.getPerformanceSalary());
                correctedStructure.setDutyAllowance(originalStructure.getDutyAllowance());
                correctedStructure.setShouldAttendanceDays(originalStructure.getShouldAttendanceDays());
                correctedStructure.setAbsenceDays(originalStructure.getAbsenceDays());
                correctedStructure.setPaidAttendanceDays(originalStructure.getPaidAttendanceDays());
                correctedStructure.setAbsenceDeduction(originalStructure.getAbsenceDeduction());
                correctedStructure.setMealAllowance(originalStructure.getMealAllowance());
                correctedStructure.setOtherAdjustment(originalStructure.getOtherAdjustment());
                correctedStructure.setMealDeduction(originalStructure.getMealDeduction());
                correctedStructure.setGrossSalary(originalStructure.getGrossSalary());
                correctedStructure.setPensionDeduction(originalStructure.getPensionDeduction());
                correctedStructure.setUnemploymentDeduction(originalStructure.getUnemploymentDeduction());
                correctedStructure.setMedicalDeduction(originalStructure.getMedicalDeduction());
                correctedStructure.setMajorMedicalDeduction(originalStructure.getMajorMedicalDeduction());
                correctedStructure.setSocialInsurancePersonal(originalStructure.getSocialInsurancePersonal());
                correctedStructure.setHousingFundPersonal(originalStructure.getHousingFundPersonal());
                correctedStructure.setSocialHousingTotal(originalStructure.getSocialHousingTotal());
                correctedStructure.setTaxableSalary(originalStructure.getTaxableSalary());
                correctedStructure.setPersonalTax(originalStructure.getPersonalTax());
                correctedStructure.setNetSalary(originalStructure.getNetSalary());

                correctedStructure.setStatus("0"); // 正常状态
                correctedStructure.setRemark("数据修正操作，原记录ID: " + correction.getOriginalStructureId());

                // 插入修正后的记录
                salaryStructureMapper.insert(correctedStructure);
            }
            return correctedStructure.getStructureId();
        } catch (Exception e) {
            // 记录日志
            log.error("执行数据修正操作失败", e);
            throw new RuntimeException("执行数据修正操作失败", e);
        }
    }
}
